package Thread;

//基于TreadDemo25阻塞队列---可以写一个简单的生产者消费者模型
//实际开发中，生产者消费者模型，往往是多个生产者多个消费者
//这里的生产者和消费者往往不仅仅是一个线程，也可能是一个独立的服务器程序，甚至是一组服务器程序
class MyBlockingQueue1{
    private String[] elems=null;
    private int head=0;
    private int tail=0;
    private int size=0;
    //准备锁对象
    private Object locker=new Object();
    public MyBlockingQueue1(int capacity){
        elems=new String[capacity];
    }
    public void put(String elem) throws InterruptedException {
        //锁加到这里和加到方法上本质是一样的，加到方法上是给this加锁，此处是给locker加锁
        synchronized (locker){
            //改为while循环意味着wait唤醒之后再判定一次条件
            //wait之前判定一次，唤醒之后判定一次，再次确认，发现队列还是满着的，就继续等待
            while(size>=elems.length){
                //队列满了
                //后续需要这个代码阻塞
                locker.wait();
            }
            //新的元素要放到tail指向的位置上
            elems[tail]=elem;
            tail++;
            if(tail>=elems.length){
                tail=0;
            }
            size++;
            //入队列成功之后唤醒
            locker.notify();
        }
    }
    public String take() throws InterruptedException {
        String elem=null;
        synchronized (locker){
            while(size==0)
            {
                //队列空了
                //后续也需要让这个代码阻塞
                locker.wait();
            }
            //取出head位置的元素并返回
            elem=elems[head];
            head++;
            if(head>=elems.length){
                head=0;
            }
            size--;
            //元素出队列成功，加上唤醒
            locker.notify();
        }
        return elem;
    }
}
public class TreadDemo26 {
    public static void main(String[] args) {
        MyBlockingQueue1 queue=new MyBlockingQueue1(1000);
        // 生产者
        Thread t1 = new Thread(() -> {
            int n = 1;
            while (true) {
                try {
                    queue.put(n + "");
                    System.out.println("生产元素 " + n);
                    n++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        // 消费者
        Thread t2 = new Thread(() -> {
            while (true) {
                try {
                    String n = queue.take();
                    System.out.println("消费元素 " + n);

                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();
    }
}
